﻿using System;
using System.Collections.Generic;
using Kugar.Core.ByteDataConverter;
using Kugar.Core.ExtMethod;

namespace Kugar.Core.Communications
{
    public class ModbusHelper
    {

        /// <summary>
        ///     从buf数据中，分离出03码的实际数据，默认2位CRC校验码
        /// </summary>
        /// <param name="buf">接收到的数据</param>
        /// <returns></returns>
        public static byte[] GetCmd03Data(byte[] buf)
        {
            return GetCmd03Data(buf, 3, 2);
        }

        /// <summary>
        ///     从buf数据中，分离出03码的实际数据，默认2位CRC校验码
        /// </summary>
        /// <param name="buf">接收到的数据</param>
        /// <param name="startindex">指定的起始索引值</param>
        /// <returns></returns>
        public static byte[] GetCmd03Data(byte[] buf, int startindex)
        {
            return GetCmd03Data(buf, startindex, 2);
        }

        /// <summary>
        ///     从buf数据中，分离出03码的实际数据
        /// </summary>
        /// <param name="buf">接收到的数据</param>
        /// <param name="startindex">指定的起始索引值</param>
        /// <param name="CRCLength">CRC校验码长度,暂时只支持2</param>
        /// <returns></returns>
        public static byte[] GetCmd03Data(byte[] buf, int startindex, int CRCLength)
        {
            if (CRCLength <= 0)
            {
                CRCLength = 2;
            }

            if (buf == null || buf.Length == 0 || startindex < 0 || startindex >= buf.Length - CRCLength)
            {
                return null;
            }

            var temp = new List<byte>(buf.Length - startindex);

            for (var i = startindex; i < buf.Length - 2; i++)
            {
                temp.Add(buf[i]);
            }

            return temp.ToArray();
        }

        /// <summary>
        ///     根据输入的参数,组织03码.默认:指令中ushort为高位在前;
        /// </summary>
        /// <param name="hostid">主机ID</param>
        /// <param name="startRegIndex">起始寄存器地址</param>
        /// <param name="length">读取寄存器个数</param>
        /// <returns>组织后的指令byte数组</returns>
        public static byte[] BuildCmd03(byte hostid, ushort startRegIndex, ushort length)
        {
            return BuildCmd03(UInt16Swap.HightBefore, hostid, startRegIndex, length);
        }

        /// <summary>
        ///     根据输入的参数,组织03码
        /// </summary>
        /// <param name="int16Swap">指令中,ushort类型值的寄存器转换方式</param>
        /// <param name="hostid">主机ID</param>
        /// <param name="startRegIndex">起始寄存器地址</param>
        /// <param name="length">读取寄存器个数</param>
        /// <returns>组织后的指令byte数组</returns>
        public static byte[] BuildCmd03(UInt16Swap int16Swap, byte hostid, ushort startRegIndex, ushort length)
        {
            if (hostid <= 0)
            {
                hostid = 1;
            }

            if (startRegIndex <= 0)
            {
                startRegIndex = 1;
            }

            if (length <= 0)
            {
                return null;
            }

            var temp = new List<byte>(10);


            temp.Add(hostid);
            temp.Add(0x03);

            temp.AddRange(ByteConverter.GetBytes(startRegIndex, int16Swap));
            temp.AddRange(ByteConverter.GetBytes(length, int16Swap));

            temp.AddRange(BitConverter.GetBytes(temp.ToArray().GetCRCCode(0, temp.Count)));

            //var temp = new byte[8];

            //temp[0] = hostid;
            //temp[1] = 0x03;


            //ByteConverter.GetBytes(length, int16Swap).CopyTo(temp, 4);

            //BitConverter.GetBytes(CRC16.CRC16.GetCRCCode(temp, 0, temp.Length - 2)).CopyTo(temp, 6);

            return temp.ToArray();
        }

        /// <summary>
        ///     从buf数据中，分离出10码的实际数据，默认2位CRC校验码
        /// </summary>
        /// <param name="buf">数据区</param>
        /// <returns></returns>
        public static Cmd10Response GetCmd10Data(byte[] buf)
        {
            return GetCmd10Data(buf, 2);
        }

        /// <summary>
        ///     从buf数据中，分离出10码的实际数据
        /// </summary>
        /// <param name="buf">数据区</param>
        /// <param name="CRCLength">CRC校验码长度</param>
        /// <returns></returns>
        public static Cmd10Response GetCmd10Data(byte[] buf, int CRCLength)
        {
            if (CRCLength <= 0)
            {
                CRCLength = 2;
            }

            if (buf == null || buf.Length == 0 || buf.Length < CRCLength + 2)
            {
                return new Cmd10Response(false, 0, null);
            }

            if (buf[1] == 0x10)
            {
                return new Cmd10Response(true, buf[2], null);
            }

            var tempCode = new byte[1] { 2 };

            return new Cmd10Response(false, 0, tempCode);
        }


        /// <summary>
        ///     根据输入的参数,组织10码,默认:指令中ushort为高位在前,一个寄存器2个字节;
        /// </summary>
        /// <param name="hostid">主机ID</param>
        /// <param name="startRegIndex">起始寄存器地址</param>
        /// <param name="data">要写入的实际数据</param>
        /// <returns>组织后的指令byte数组</returns>
        public static byte[] BuildCmd10(byte hostid, ushort startRegIndex, byte[] data)
        {
            return BuildCmd10(UInt16Swap.HightBefore, hostid, startRegIndex, (ushort)(data.Length / 2), data);
        }

        /// <summary>
        ///     根据输入的参数,组织10码.默认:指令中ushort为高位在前;
        /// </summary>
        /// <param name="hostid">主机ID</param>
        /// <param name="startRegIndex">起始寄存器地址</param>
        /// <param name="length">写入寄存器个数</param>
        /// <param name="data">要写入的实际数据</param>
        /// <returns>组织后的指令byte数组</returns>
        public static byte[] BuildCmd10(byte hostid, ushort startRegIndex, ushort length, byte[] data)
        {
            return BuildCmd10(UInt16Swap.HightBefore, hostid, startRegIndex, length, data);
        }

        /// <summary>
        ///     根据输入的参数,组织10码
        /// </summary>
        /// <param name="int16Swap">指令中,ushort类型值的寄存器转换方式</param>
        /// <param name="hostid">主机ID</param>
        /// <param name="startRegIndex">起始寄存器地址</param>
        /// <param name="length">写入寄存器个数</param>
        /// <param name="data">要写入的实际数据</param>
        /// <returns>组织后的指令byte数组</returns>
        public static byte[] BuildCmd10(UInt16Swap int16Swap, byte hostid, ushort startRegIndex, ushort length, byte[] data)
        {
            if (data == null || data.Length <= 0 || data.Length > 240 || length <= 0)
            {
                return null;
            }

            var tempdata = new List<byte>();


            tempdata.Add(hostid);
            tempdata.Add(0x10);

            tempdata.AddRange(ByteConverter.GetBytes(startRegIndex, int16Swap));//起始地址

            tempdata.AddRange(ByteConverter.GetBytes(length, int16Swap));//寄存器数量

            tempdata.Add((byte)(length * 2));

            tempdata.AddRange(data);

            tempdata.AddRange(ByteConverter.GetBytes(tempdata.ToArray().GetCRCCode(0, tempdata.Count), UInt16Swap.HightBefore));

            return tempdata.ToArray();
        }


        /// <summary>
        ///     10码返回数据包解析后的数据
        /// </summary>
        public class Cmd10Response
        {
            internal Cmd10Response(bool _isSuccess, int writeCount, byte[] errorCode)
            {
                IsSuccess = _isSuccess;
                WriteCount = writeCount;
                ErrorCode = errorCode;
            }

            /// <summary>
            ///     10码是否成功，成功为true，失败为false
            /// </summary>
            public bool IsSuccess { protected set; get; }

            /// <summary>
            ///     总共写入的数据个数
            /// </summary>
            public int WriteCount { protected set; get; }

            /// <summary>
            ///     错误功能码
            /// </summary>
            public byte[] ErrorCode { protected set; get; }
        }
    }
}
